package multiplex.dataaccess.dao;

import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import multiplex.dataaccess.DaoException;
import multiplex.model.Filme;
import multiplex.model.PromocaoFilme;

public class PromocaoFilmeDao 
		extends AbstractDao implements IPromocaoDao<PromocaoFilme> {
	
	public PromocaoFilme get(int id) throws DaoException {
		try{
			PreparedStatement st = getConnection().prepareStatement("SELECT Promocao.id AS id, " +
					"Promocao.nome AS nome, Promocao.desconto AS desconto, Promocao.descricao AS descricao, " +
					"PromocaoFilme.Filme_id AS Filme_id, PromocaoFilme.dia AS dia FROM " +
					"PromocaoFilme, Promocao WHERE PromocaoFilme.Promocao_id = Promocao.id AND " +
					"Promocao.id = ?");
			st.setInt(1, id);
			ResultSet rs = st.executeQuery();
			if(rs.next()){
				PromocaoFilme promocaoFilme = new PromocaoFilme();
				fillPromocaoFilme(promocaoFilme, rs);
				st.close();
				return promocaoFilme;
			}
		} catch(Exception e){
			throw new DaoException(e);
		}
		return null;
	}

	public List<PromocaoFilme> getAll() throws DaoException {
		List<PromocaoFilme> promocaoFilmeList = new ArrayList<PromocaoFilme>();
		try{
			PreparedStatement st = getConnection().prepareStatement("SELECT Promocao.id AS id, " +
					"Promocao.nome AS nome, Promocao.desconto AS desconto, Promocao.descricao AS descricao, " +
					"PromocaoFilme.Filme_id AS Filme_id, PromocaoFilme.dia AS dia FROM " +
					"PromocaoFilme, Promocao WHERE PromocaoFilme.Promocao_id = Promocao.id");
			ResultSet rs = st.executeQuery();
			while(rs.next()){
				PromocaoFilme promocaoFilme = new PromocaoFilme();
				fillPromocaoFilme(promocaoFilme, rs);
				promocaoFilmeList.add(promocaoFilme);
			}
			st.close();
			return promocaoFilmeList;
		}catch(Exception e){
			throw new DaoException(e);
		}
	}
	
	public List<PromocaoFilme> getAllFromFilme(Filme filme) throws DaoException {
		List<PromocaoFilme> promocaoFilmeList = new ArrayList<PromocaoFilme>();
		try{
			PreparedStatement st = getConnection().prepareStatement("SELECT Promocao.id AS id, " +
					"Promocao.nome AS nome, Promocao.desconto AS desconto, Promocao.descricao AS descricao, " +
					"PromocaoFilme.Filme_id AS Filme_id, PromocaoFilme.dia AS dia FROM " +
					"PromocaoFilme, Promocao WHERE " +
					"PromocaoFilme.Promocao_id = Promocao.id AND " +
					"PromocaoFilme.Filme_id = ?");
			st.setInt(1, filme.getId());
			ResultSet rs = st.executeQuery();
			while(rs.next()){
				PromocaoFilme promocaoFilme = new PromocaoFilme();
				fillPromocaoFilme(promocaoFilme, rs);
				promocaoFilmeList.add(promocaoFilme);
			}
			st.close();
			return promocaoFilmeList;
		}catch(Exception e){
			throw new DaoException(e);
		}
	}

	public void save(PromocaoFilme promocaoFilme) throws DaoException {
		try {
			try{
				getConnection().setAutoCommit(false);
				PreparedStatement stPromocao = getConnection().prepareStatement("INSERT INTO " +
						"Promocao(nome, descricao, desconto) VALUES (?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
				fillPreparatedStatementPromocao(stPromocao, promocaoFilme);
				stPromocao.execute();
				ResultSet rs = stPromocao.getGeneratedKeys();
				rs.next();
				promocaoFilme.setId(rs.getInt(1));
				PreparedStatement stPromocaoFilme = getConnection().prepareStatement(
						"INSERT INTO PromocaoFilme (Promocao_id, Filme_id, dia) VALUES (?,?,?)");
				fillPreparatedStatementPromocaoFilme(stPromocaoFilme, promocaoFilme);
				stPromocaoFilme.execute();
				getConnection().commit();
				stPromocao.close();
				stPromocaoFilme.close();
			} catch(Throwable e){
				getConnection().rollback();
				throw new DaoException(e);
			} finally {
				getConnection().setAutoCommit(true);
			}
		} catch (Exception e) {
			throw new DaoException(e);
		}
	}
	
	public void update(PromocaoFilme promocaoFilme) throws DaoException {
		try {
			try{
				getConnection().setAutoCommit(false);
				PreparedStatement stPromocao = getConnection().prepareStatement("UPDATE Promocao " +
						"SET nome=?, descricao=?, desconto=? WHERE id=?");
				fillPreparatedStatementPromocao(stPromocao, promocaoFilme);
				stPromocao.setInt(4, promocaoFilme.getId());
				PreparedStatement stPromocaoFilme = getConnection().prepareStatement(
						"UPDATE PromocaoFilme SET Filme_id=?, dia=? WHERE Promocao_id=?");
				fillPreparatedStatementPromocaoFilme(stPromocaoFilme, promocaoFilme);
				stPromocao.execute();
				stPromocaoFilme.execute();
				getConnection().commit();
				stPromocao.close();
				stPromocaoFilme.close();
			} catch(Throwable e){
				getConnection().rollback();
				throw new DaoException(e);
			} finally {
				getConnection().setAutoCommit(true);
			}
		} catch (Exception e) {
			throw new DaoException(e);
		}
	}

	public void remove(PromocaoFilme promocaoFilme) throws DaoException {
		// PromocaoFilme é apagada com base no CASCADE ALL
		try{
			PreparedStatement st = getConnection().prepareStatement(
					"DELETE FROM Promocao WHERE id=?");
			st.setInt(1, promocaoFilme.getId());
			st.execute();
			st.close();		
		}catch(Throwable e){
			throw new DaoException(e);
		}	
	}
	
	private void fillPromocaoFilme(PromocaoFilme promocaoFilme, ResultSet rs) throws SQLException {
		promocaoFilme.setId(rs.getInt("id"));
		promocaoFilme.setNome(rs.getString("nome"));
		promocaoFilme.setDescricao(rs.getString("descricao"));
		promocaoFilme.setDesconto(rs.getFloat("desconto"));
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(rs.getDate("dia"));
		promocaoFilme.setDia(calendar);
		FilmeDao filmeDao = new FilmeDao();
		Filme filme = filmeDao.get(rs.getInt("Filme_id"));
		promocaoFilme.setFilme(filme);
	}
	
	private void fillPreparatedStatementPromocao(PreparedStatement st, PromocaoFilme promocaoFilme) 
			throws SQLException {
		st.setString(1,promocaoFilme.getNome());
		st.setString(2, promocaoFilme.getDescricao());
		st.setDouble(3,promocaoFilme.getDesconto());
	}
	
	private void fillPreparatedStatementPromocaoFilme(PreparedStatement st, PromocaoFilme promocaoFilme) 
			throws SQLException {
		st.setInt(1,promocaoFilme.getId());
		st.setInt(2, promocaoFilme.getFilme().getId());
		st.setDate(3, new Date(promocaoFilme.getDia().getTimeInMillis()));
	}
	
}
